﻿namespace Contoso.ActiveDirectory {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.DirectoryServices;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    #endregion

    public class ContactMethods {

        /// <summary>
        /// Creates a mail-enabled Contact
        /// </summary>
        /// <param name="ouDN">The distinguished name of the organizational unit where the contact will be created</param>
        /// <param name="cn">The common name</param>
        /// <param name="displayName">The display name</param>
        /// <param name="givenName">The given name</param>
        /// <param name="legacyExchangeDN">The legacyExchangeDN</param>
        /// <param name="mail">The mail address</param>
        /// <param name="mailNickname">The mailNickname (alias)</param>
        /// <param name="sn">The surname</param>
        /// <param name="targetAddress">The targetAddress (external address)</param>
        /// <param name="showInAddressBook">The address books where the contact may appear</param>
        /// <returns>Distinguished Name of the Contact</returns>
        public string CreateMailEnabledContact(string ouDN, string cn, string displayName, string givenName, string legacyExchangeDN,
            string mail, string mailNickname, string sn, string targetAddress, IEnumerable<string> showInAddressBook = null) {

            #region Validation
            if (string.IsNullOrWhiteSpace(ouDN)) {
                throw new ArgumentNullException("ouDN");
            }
            if (string.IsNullOrWhiteSpace(cn)) {
                throw new ArgumentNullException("cn");
            }
            if (string.IsNullOrWhiteSpace(displayName)) {
                throw new ArgumentNullException("displayName");
            }
            if (string.IsNullOrWhiteSpace(givenName)) {
                throw new ArgumentNullException("givenName");
            }
            if (string.IsNullOrWhiteSpace(legacyExchangeDN)) {
                throw new ArgumentNullException("legacyExchangeDN");
            }
            if (string.IsNullOrWhiteSpace(mail)) {
                throw new ArgumentNullException("mail");
            }
            if (string.IsNullOrWhiteSpace(mailNickname)) {
                throw new ArgumentNullException("mailNickname");
            }
            if (string.IsNullOrWhiteSpace(sn)) {
                throw new ArgumentNullException("sn");
            }
            if (string.IsNullOrWhiteSpace(targetAddress)) {
                throw new ArgumentNullException("targetAddress");
            }
            #endregion

            var methodParameters = new MethodParameters() {
                Cn = cn,
                DisplayName = displayName,
                GivenName = givenName,
                LegacyExchangeDN = legacyExchangeDN,
                Mail = mail,
                MailNickname = mailNickname,
                OUDN = ouDN.Trim(),
                ProxyAddresses = new List<string>() { string.Format("SMTP:{0}", targetAddress), string.Format("smtp:{0}", mail)},
                ServerNameOrAdjustedBindPath = null,
                ShowInAddressBook = showInAddressBook,
                Sn = sn,
                TargetAddress = targetAddress
            };

            string contactDN = ConnectionManager.DirectoryServerHandler<MethodParameters, string>(
                ref methodParameters,
                (x) => {
                    methodParameters.ServerNameOrAdjustedBindPath = ADDataAccess.GetAdjustedBindPath(forupdate: true, bindPath: methodParameters.OUDN);

                    #region Validation
                    if (!ADDataAccess.ObjectExists(methodParameters.ServerNameOrAdjustedBindPath)) {
                        throw new ApplicationException(string.Format("Path does not exist: {0}", methodParameters.ServerNameOrAdjustedBindPath));
                    }
                    #endregion

                    using (var ouDirectoryEntry = new DirectoryEntry(methodParameters.ServerNameOrAdjustedBindPath, null, null, methodParameters.AuthenticationTypes))
                    using (var contactDirectoryEntry = ouDirectoryEntry.Children.Add("CN=" + methodParameters.Cn, "contact")) {

                        contactDirectoryEntry.Properties["displayName"].Value = methodParameters.DisplayName;
                        contactDirectoryEntry.Properties["givenName"].Value = methodParameters.GivenName;
                        // example: /o=Contoso Corporation/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=Jane Doe
                        contactDirectoryEntry.Properties["legacyExchangeDN"].Value = methodParameters.LegacyExchangeDN;
                        contactDirectoryEntry.Properties["mail"].Value = methodParameters.Mail;
                        contactDirectoryEntry.Properties["mailNickname"].Value = methodParameters.MailNickname;
                        contactDirectoryEntry.Properties["proxyAddresses"].Value = methodParameters.ProxyAddresses.ToArray();
                        contactDirectoryEntry.Properties["sn"].Value = methodParameters.Sn;
                        contactDirectoryEntry.Properties["targetAddress"].Value = methodParameters.TargetAddress;
                        contactDirectoryEntry.Properties["msExchRecipientDisplayType"].Value = (int)MSExchRecipientDisplayType.RemoteMailUser;

                        if (showInAddressBook != null) {
                            contactDirectoryEntry.Properties["showInAddressBook"].Value = methodParameters.ShowInAddressBook.ToArray();
                        }

                        contactDirectoryEntry.CommitChanges();
                        methodParameters.CreatedObjectDN = ADDataAccess.GetDNFromLdapDN(contactDirectoryEntry.Path);

                    }

                    return methodParameters.CreatedObjectDN;
                });

            if (string.IsNullOrWhiteSpace(contactDN)) {
                throw new ApplicationException("Contact DN not returned when creating contact");
            }

            return contactDN;
        }
    }
}
